home *** CD-ROM | disk | FTP | other *** search
/ Disc to the Future 2 / Disc to the Future Part II Programmer's Reference (Wayzata Technology)(6013)(1992).bin / MAC / THINKC / 5 / GRAF3D / GRAF3D_D.OC < prev    next >
Text File  |  1992-07-19  |  12KB  |  383 lines

  1. Graf3D: The Three-dimensional Graphics Library
  2.  
  3. Graf3D draws three dimensional graphics in the two-dimensional environment 
  4. provided by Quickdraw.
  5.  
  6. Graf3D presents a "camera-eye view" of the objects drawn.  With Graf3D 
  7. procedures, the programmer sets the camera's location and field-of-view, 
  8. as well as the location and orientation of the object being viewed.  Graf3D 
  9. manages a "viewing pyramid" whose apex is at the camera's eye and whose base is 
  10. Graf3D's "ViewPort".  The Graf3D package will clip objects being viewed to this 
  11. pyramid.
  12.  
  13. The Graf3D package makes extensive use of the "fixed point" data type.  "Fixed" 
  14. is defined as:
  15.     type 
  16.         fixed = longint;
  17. The high order word of a fixed variable is the integer part;  the low order 
  18. word is the fraction part.  Values are represented in units of 1/65536ths.  For 
  19. example, the number 2.5 would be represented by a "2" in the high word and a 
  20. 32768 in the low order word (32768/65536 = .5), which would yield the longint 
  21. value 163840.  Another way to think of it is that the value of a "fixed" 
  22. variable is the value of the longint divided by 65536.  For more detail see 
  23. Inside Macintosh in the "Introduction to Memory Management" chapter.  
  24.  
  25.  
  26. Graf3D Types
  27.  
  28. Point3D
  29. A Point3D is a record containing three "fixed" coordinates.
  30.  
  31.     Point3D = record
  32.                 x : fixed;
  33.                 y : fixed;
  34.                 z : fixed;
  35.             end;
  36.  
  37. Point2D
  38. A Point2D is a record containing two "fixed" coordinates.
  39.  
  40.     Point2D = record
  41.                 x : fixed;
  42.                 y : fixed;
  43.             end;
  44.  
  45.  
  46. XfMatrix
  47. An XfMatrix is a 4x4 matrix of "fixed" values that holds the transformation 
  48. equation for points to be viewed.
  49.  
  50.         XfMatrix = array [0..3, 0..3] of fixed;
  51.  
  52. Port3D
  53. The Port3D contains all of the state variables necessary to map the three 
  54. dimensional coordinates of the image into the two dimensional screen coordinates.  
  55. "GrPort" is the pointer to the QuickDraw grafPort associated with this Port3D.  
  56. "viewRect" is the viewing rectangle within the Port3D.  "xLeft, yTop, xRight, 
  57. yBottom" are the coordinates of the viewRect in the three-dimensional "world".  
  58. "pen" is the three dimensional pen location.  "penPrime" is the pen location 
  59. transformed by the "xForm" matrix.  "eye" is the position of the camera in 
  60. three-dimensional coordinates.  "hSize, vSize" are the half-width and half-
  61. height of the viewPort in screen coordinates.  "hCenter, vCenter" are the 
  62. coordinates of the center of the viewPort in screen coordinates.  "xCotan, 
  63. yCotan" are the cotangents of the horizontal and vertical viewing angles.  
  64. "ident" is a boolean which is true when "xForm" is equal to the identity 
  65. transformation.  "xForm" is the transformation matrix.
  66.  
  67.     Port3DPtr = ^Port3D;
  68.     Port3D = record
  69.                 GrPort : GrafPtr;
  70.                 viewRect : Rect;
  71.                 xLeft, yTop, xRight, yBottom : fixed;
  72.                 pen, penPrime, eye : Point3D;
  73.                 hSize, vSize : fixed;
  74.                 hCenter, vCenter : fixed;
  75.                 xCotan, yCotan : fixed;
  76.                 ident : BOOLEAN;
  77.                 xForm : XfMatrix;
  78.             end;
  79.  
  80.  
  81.  
  82.  
  83. Graf3D Procedures and Functions
  84.  
  85. Graf3D is a three dimensional Quickdraw package.  Its types, variable and 
  86. routines mimic Quickdraw in many ways.  The following procedures and functions 
  87. are provided in the Graf3D package:
  88.  
  89. Graf3DPort port initialization routines:
  90.  
  91. var thePort3D : Port3DPtr;
  92. procedure InitGrf3D (globalPtr : Ptr);
  93.  
  94. InitGrf3D initializes the Graf3D drawing environment.  This procedure should be 
  95. called once and only once per program execution, after Quickdraw is initialized.  
  96. "globalPtr" is a pointer to the storage you wish to use for the Graf3D global 
  97. variables.  Lightspeed Pascal programmers should always pass "@thePort3D" in 
  98. this parameter.
  99.  
  100. procedure Open3DPort (port : Port3DPtr);
  101. Open3DPort opens and initializes a 3D GrafPort whose space is pointed to by the 
  102. parameter "port".  It also sets "thePort3D" (the current Graf3DPort) to "port".
  103.  
  104. procedure SetPort3D (port : Port3DPtr);
  105. SetPort3D sets the current Graf3DPort ("thePort3D") to "port" and calls SetPort 
  106. for "port"'s associated grafPort.
  107.  
  108. procedure GetPort3D (var port : Port3DPtr);
  109. GetPort3D returns a pointer to the current graf3DPort in "port".  This is useful 
  110. when the programmer wishes to change ports for drawing something and then 
  111. restore the port before proceeding with the rest of the program.  For example:
  112.  
  113. var
  114.     myPort, savePort: Port3DPtr;
  115. ...
  116.     GetPort3D( savePort );        { save the current port }
  117.     SetPort3D( myPort );        { set the port to my own }
  118.     { I can do my drawing now╔ }
  119.     SetPort3D( savePort );        { restore the port to the one saved }
  120.  
  121.  
  122. Pen movement and drawing
  123.  
  124. The following routines are used to move the pen in the 3D space and draw lines 
  125. in the space.  NOTE:  The coordinates in these routines are specified in "fixed 
  126. point" notation (NOT INTEGERS as in Quickdraw).
  127.  
  128. procedure MoveTo2D (x, y : fixed);
  129. procedure MoveTo3D (x, y, z : fixed);
  130. These procedures move the pen to the designated coordinates.  (MoveTo2D moves 
  131. without changing the Z-coordinate.)
  132.  
  133. procedure LineTo2D (x, y : fixed);
  134. procedure LineTo3D (x, y, z : fixed);
  135. These procedures draw lines from the current pen position to the given 
  136. coordinates (LineTo2D draws without changing the z-coordinate, i.e. the line is 
  137. drawn in the same z-plane.)
  138.  
  139. procedure Move2D (dx, dy : fixed);
  140. procedure Move3D (dx, dy, dz : fixed);
  141. These procedures move the pen by the specified amounts relative to the current 
  142. pen position.  (Move2D moves without changing the Z-coordinate.)
  143.  
  144. procedure Line2D (dx, dy : fixed);
  145. procedure Line3D (dx, dy, dz : fixed);
  146. These procedures draw lines from the current pen position to the given offsets 
  147. relative to the current pen position (Line2D draws without changing the 
  148. z-coordinate, i.e. the line is drawn in the same z-plane.)
  149.  
  150. function Clip3D (src1, src2 : Point3D;  var dst1, dst2 : POINT): boolean;
  151. Clip3D clips a three-dimensional line segment to the viewing pyramid and returns 
  152. the clipped line projected onto screen coordinates.  Clip3D returns true if any 
  153. part of the line is visible.
  154.  
  155. procedure SetPt3D ( var pt3D : Point3D;  x, y, z : fixed);
  156. SetPt3D assigns the 3 fixed numbers "x,y,z" to the point pt3D.
  157.  
  158. procedure SetPt2D ( var pt2D : Point2D;  x, y : fixed);
  159. SetPt3D assigns the 2 fixed numbers "x,y" to the point pt2D.
  160.  
  161.  
  162. Setting up the point of view
  163.  
  164. The following three procedures set the position and field-of-view of the "point 
  165. of view".
  166.  
  167. procedure LookAt (left, top, right, bottom : fixed);
  168. LookAt specifies the real number x,y coordinates of the viewing rectangle.
  169.  
  170. procedure ViewPort (r : Rect);
  171. ViewPort specifies where to put the image in the grafPort.  The ViewPort 
  172. rectangle is specified in integer coordinates and tells where to map the LookAt 
  173. coordinates.
  174.  
  175. procedure ViewAngle (angle : fixed);
  176. ViewAngle controls the amount of perspective by specifying the horizontal angle 
  177. subtended by the viewing rectangle.  Typical ViewAngles are 0í (no perspective), 
  178. 10í (telephoto lens), 25í (normal human eye), and 80í (wide angle lens).
  179.  
  180.  
  181. Transformation matrix procedures
  182.  
  183. The following procedures modify the transformation matrix that is used to plot 
  184. the points in the viewing coordinates.
  185.  
  186. procedure Identity;
  187. Identity sets the transformation matrix to the identity matrix.
  188.  
  189. procedure Scale (xFactor, yFactor, zFactor : fixed);
  190. Scale modifies the transformation matrix so as to shrink or expand the image by 
  191. the factors specified.
  192.  
  193. procedure Translate (dx, dy, dz : fixed);
  194. Transform modifies the transformation matrix so as to displace the image by the 
  195. specified amounts in the three coordinates.
  196.  
  197. procedure Pitch (xAngle : fixed);
  198. Pitch modifies the transformation matrix so as to rotate "xangle" degrees around 
  199. the x axis.  Positive values cause a clockwise rotation when looking at the 
  200. origin from positive x.
  201.  
  202. procedure Yaw (yAngle : fixed);
  203. Yaw modifies the transformation matrix so as to rotate "yAngle" degrees around 
  204. the y axis.  Positive values cause a clockwise rotation when looking at the 
  205. origin from positive y.
  206.  
  207. procedure Roll (zAngle : fixed);
  208. Roll modifies the transformation matrix so as to rotate "zAngle" degrees around 
  209. the z axis.  Positive values cause a clockwise rotation when looking at the 
  210. origin from positive z.
  211.  
  212. procedure Skew (zAngle : fixed);
  213. Skew modifies the transformation matrix so as to skew the image by "zAngle" 
  214. degrees around the z axis.  Skew only changes the x axis.  Positive values cause 
  215. a clockwise rotation when looking at the origin from positive z.
  216.  
  217. procedure TransForm (src : Point3D;  var dst : Point3D);
  218. Transform applies the transformation matrix to the "src" point, and returns the 
  219. result in "dst".
  220.  
  221.  
  222.  
  223. program boxes;
  224.     uses
  225.         Graf3D;
  226.  
  227.     const
  228.         boxcount = 10;
  229.  
  230.     type
  231.         box3d = record
  232.                 pt1 : Point3D;
  233.                 pt2 : point3D;
  234.                 dist : real;
  235.             end;
  236.  
  237.     var
  238.         GPort1 : GrafPort;
  239.         GPort2 : Port3D;
  240.         myPort : GrafPtr;
  241.         myPort3D : Port3DPtr;
  242.         boxArray : array[0..boxCount] of Box3D;
  243.         nBoxes : integer;
  244.         i : integer;
  245.         ph : picHandle;
  246.         r : rect;
  247.  
  248.     function HeapError (hz : QDPtr;
  249.                 bytesNeeded : integer) : integer;
  250.     begin
  251.         writeln('The heap is full!!!');
  252.     end;
  253.  
  254.     function Distance (pt1, pt2 : Point3D) : real;
  255.         var
  256.             dx, dy, dz : real;
  257.     begin
  258.         dx := pt2.x - pt1.x;
  259.         dy := pt2.y - pt1.y;
  260.         dz := pt2.z - pt1.z;
  261.         Distance := sqrt(dx * dx + dy * dy + dz * dz);
  262.     end;
  263.  
  264.     procedure  MakeBox;
  265.         label
  266.             99;
  267.         var
  268.             myBox : Box3D;
  269.             i, j, k, v : integer;
  270.             p1, p2 : point3D;
  271.             myRect : Rect;
  272.             testRect : Rect;
  273.     begin
  274.         p1.x := (Random mod 140 - 85) * 65536;
  275.         p1.y := (Random mod 140 - 80) * 65536;
  276.         p1.z := 0;
  277.         p2.x := p1.x + (10 + abs(Random) mod 30) * 65536;
  278.         p2.y := p1.y + (10 + abs(Random) mod 45) * 65536;
  279.         p2.z := p1.z + (10 + abs(Random) mod 35) * 65536;
  280.         SetRect(myRect, round(p1.x div 65536), round(p1.y div 65536), round(p2.x div 65536),                 round(p2.y div 65536));
  281.         for i := 1 to nBoxes - 1 do
  282.             begin
  283.                 with boxArray[i] do
  284.                     SetRect(testRect, round(pt1.x DIV 65536), round(pt1.y DIV 65536),                             round(pt2.x DIV 65536), round(pt2.y DIV 65536));
  285.                 if sectrect(myRect, testRect, testRect) then
  286.                     goto 99;
  287.             end;
  288.         myBox.pt1 := p1;
  289.         myBox.pt2 := p2;
  290.         p1.x := (p1.x + p2.x) DIV 2;
  291.         p1.y := (p1.y + p2.y) DIV 2;
  292.         p1.z := (p1.z + p2.z) DIV 2;
  293.         Transform(p1, p2);
  294.         myBox.dist := Distance(p2, myPort3D^.eye);
  295.         i := 0;
  296.         boxArray[nBoxes].dist := myBox.dist;
  297.         while myBox.dist > boxArray[i].dist do
  298.             i := i + 1;
  299.         for j := nBoxes downto i + 1 do
  300.             boxArray[j] := boxArray[j - 1];
  301.         boxArray[i] := myBox;
  302.         nBoxes := nBoxes + 1;
  303. 99 :
  304.     end;
  305.  
  306.     procedure drawBox (pt1, pt2 : Point3D);
  307.         var
  308.             tempRgn : RgnHandle;
  309.     begin
  310.         tempRgn := NewRgn;
  311.         OpenRgn;
  312.         MoveTo3D(pt1.x, pt1.y, pt1.z);
  313.         LineTo3D(pt1.x, pt1.y, pt2.z);
  314.         LineTo3D(pt2.x, pt1.y, pt2.z);
  315.         LineTo3D(pt2.x, pt1.y, pt1.z);
  316.         LineTo3D(pt1.x, pt1.y, pt1.z);
  317.         CloseRgn(tempRgn);
  318.         FillRgn(tempRgn, white);
  319.         FrameRgn(tempRgn);
  320.         OpenRgn;
  321.         MoveTo3D(pt1.x, pt1.y, pt2.z);
  322.         LineTo3D(pt1.x, pt2.y, pt2.z);
  323.         LineTo3D(pt2.x, pt2.y, pt2.z);
  324.         LineTo3D(pt2.x, pt1.y, pt2.z);
  325.         LineTo3D(pt1.x, pt1.y, pt2.z);
  326.         CloseRgn(tempRgn);
  327.         FillRgn(tempRgn, gray);
  328.         OpenRgn;
  329.         MoveTo3D(pt2.x, pt1.y, pt1.z);
  330.         LineTo3D(pt2.x, pt1.y, pt2.z);
  331.         LineTo3D(pt2.x, pt2.y, pt2.z);
  332.         LineTo3D(pt2.x, pt2.y, pt1.z);
  333.         LineTo3D(pt2.x, pt1.y, pt1.z);
  334.         CloseRgn(tempRgn);
  335.         FillRgn(tempRgn, black);
  336.         PenPat(white);
  337.         MoveTo3D(pt2.x, pt2.y, pt2.z);
  338.         LineTo3D(pt2.x, pt2.y, pt1.z);
  339.         LineTo3D(pt2.x, pt1.y, pt1.z);
  340.         PenNormal;
  341.         DisposeRgn(tempRgn);
  342.     end;
  343.  
  344. begin
  345.     setrect(r, 0, 40, 512, 342);
  346.     SetDrawingRect(r);
  347.     InitGrf3D(@thePort3D);
  348.     showdrawing;
  349.     GetPort(myPort);
  350.     ph := OpenPicture(myPort^.portRect);
  351.     showpen;
  352.     myPort3D := @GPort2;
  353.     Open3DPort(myPort3D);
  354.     ViewPort(myPort^.portRect);
  355.     LookAt($FF9C0000, $4B0000, $640000, $FFB50000);
  356.     ViewAngle($200000);
  357.     Identity;
  358.     Roll($140000);
  359.     Pitch($460000);
  360.     PenPat(white);
  361.     BackPat(black);
  362.     EraseRect(myPort^.portRect);
  363.     for i := -10 to 10 do
  364.         begin
  365.             MoveTo3D(i * 10 * 65536, -100 * 65536, 0);
  366.             LineTo3D(i * 10 * 65536, 100 * 65536, 0);
  367.         end;
  368.     for i := -10 to 10 do
  369.         begin
  370.             MoveTo3D(-100 * 65536, i * 10 * 65536, 0);
  371.             LineTo3D(100 * 65536, i * 10 * 65536, 0);
  372.         end;
  373.     nBoxes := 0;
  374.     repeat
  375.         MakeBox
  376.     until nBoxes = boxCount;
  377.     for i := nBoxes - 1 downto 0 do
  378.         DrawBox(boxArray[i].pt1, boxArray[i].pt2);
  379.     HidePen;
  380.     ClosePicture;
  381.     readln
  382. end.
  383.